# -*- encoding: utf-8 -*-
from django.db import models
from django.db.models import permalink
from django.contrib.auth.models import User
from django.conf import settings
from django.template.defaultfilters import slugify
from django.utils.translation import ugettext_lazy as _


class PublishedManager(models.Manager):
    def get_query_set(self):
        return super(PublishedManager, self).get_query_set().filter(is_published=True)


class Category(models.Model):
    """A simple Category for Post objects
    
    # Create a simple category, not giving a slug
    >>> cat1 = Category(title='testcat1', description='first test category')
    >>> cat1.save()

    # If no slug is given, a unique slug will be created from the title
    >>> cat2 = Category(title='testcat1', description='same title as previous!')
    >>> cat2.save()
    >>> cat2.slug == "testcat1-1"
    True

    # Different object creation syntax -- still creates unique slug
    >>> cat3 = Category.objects.create(title="testcat1", description="again the same title!")
    >>> cat3.slug == "testcat1-2"
    True

    # Create a duplicate -- db should throw an exception (slug is supposed to be unique)
    # WARNING: doesn't throw an exception with at least sqlite!
    >>> cat4 = Category(title="Title different", description="but slug is already in db", slug="testcat1")
    >>> cat4.save()

    # Creating a category without a title should result in a db exception
    # WARNING: doesn't throw an exception with at least sqlite!
    >>> cat5 = Category(description="No title! but a slug", slug="no-title")
    >>> cat5.save()

    >>> from django.core.urlresolvers import reverse
    >>> cat5.get_absolute_url() == reverse('wagglyblog_category', None, (cat5.slug,))
    True
    >>> cat5.get_absolute_url()
    '/categories/no-title/'

    """
    title = models.CharField(_('Title'), max_length=50)
    description = models.TextField(_('Description'))
    slug = models.SlugField(_('Slug'), primary_key=True, unique=True)

    class Meta:
        verbose_name = _('Category')
        verbose_name_plural = _('Categories')
        ordering = ['title']

    def __unicode__(self):
        return self.title

    def save(self, **kwargs):
        # TODO: Needs to be refactored out
        # WARNING: isn't really a good solution performance-wise
        if not self.slug:
            slug = slugify(self.title)
            suffix = ""
            while Category.objects.filter(slug="%s%s" % (slug, suffix)):
                try:
                    suffix = int(suffix[1:])
                    suffix = suffix + 1
                except (ValueError,):
                    suffix = 1
                suffix = "-%i" % suffix
            self.slug = slug + suffix
        super(Category, self).save(**kwargs)

    @permalink
    def get_absolute_url(self):
        return ('wagglyblog_category', (self.slug,))


class Post(models.Model):
    """Simple blog post model
    
    # Needed imports
    >>> from django.contrib.auth.models import User
    
    # Create a user
    >>> user = User.objects.create_user('admin','admin@example.com','admin')
    
    # Create a post, omittin 'slug'
    >>> post = Post.objects.create(author=user, title='Hello Blogsters', text="my first post", is_published=True)
    >>> post.id
    1
    >>> post.slug
    u'hello-blogsters'
    >>> post.category_list
    u''
    
    # Create some categories and add them to the post
    >>> test = Category.objects.create(title="test",description="blabla")
    >>> baz = Category.objects.create(title="Baz", description="bla blub")
    >>> post.categories.add(test)
    >>> post.categories.add(baz)

    # Get a comma-separated string of category titles
    >>> post.category_list == u'test, Baz' or post.category_list == u'Baz, test'
    True

    # Access next/previous published entries -- but there are none
    >>> post.get_next_published() == None == post.get_previous_published()
    True

    # Create post with is_published=False (default)
    >>> post2 = Post.objects.create(author=user, title="Draft", text="Not supposed to be published!")

    # Get all posts -- even not yet published ones
    >>> Post.objects.all()
    [<Post: Draft>, <Post: Hello Blogsters>]

    # Fetch a list of published posts
    >>> Post.published.all()
    [<Post: Hello Blogsters>]

    # Publish post2 and check get_previous_published()
    >>> post2.is_published = True
    >>> post2.save()
    >>> post2.get_previous_published()
    <Post: Hello Blogsters>
    
    # get_next_published() is still returning None as there is no next (published) post
    >>> post2.get_next_published() == None
    True
    
    """
    author = models.ForeignKey(User, verbose_name=_('Author'), related_name="blogs")
    title  = models.CharField(_('Title'), max_length=120)
    text   = models.TextField(_('Text'))
    slug   = models.SlugField(_('Slug'), unique_for_date="pub_date")
    pub_date   = models.DateTimeField(_('Pub date'), auto_now_add=True)
    categories = models.ManyToManyField(Category, verbose_name=_('Categories'), blank=True, null=True)
    allow_comments = models.BooleanField(_('Enable Comments'), default=True)    # TODO: rename to enable_comments
    is_published   = models.BooleanField(_('Is published'), default=False)

    objects   = models.Manager()
    published = PublishedManager()

    class Meta:
        verbose_name = _('Post')
        verbose_name_plural = _('Posts')
        ordering = ('-pub_date',)
        get_latest_by = "pub_date"

    def __unicode__(self):
        return self.title

    def save(self):
        # TODO: Needs to be refactored out
        # WARNING: isn't really a good solution performance-wise
        if not self.slug:
            slug = slugify(self.title)
            suffix = ""
            while Post.objects.filter(slug="%s%s" % (slug, suffix)):
                try:
                    suffix = int(suffix[1:])
                    suffix = suffix + 1
                except (ValueError,):
                    suffix = 1
                suffix = "-%i" % suffix
            self.slug = slug + suffix
        super(Post, self).save()

    @permalink
    def get_absolute_url(self):
        """Returns the absolute URL to the specific post

        Depending on the value of settings.WAGGLYBLOG_URL_STYLE::

            "short" results in a path like /blog/1/ (where blog/ is the prefix to wagglyblog)
            "full" results in date-based URLS /blog/2007/9/5/example-post/

        """
        if getattr(settings, 'WAGGLYBLOG_URL_STYLE', 'full') == 'short':
            return ('wagglyblog_short_detail', (self.id,))
        return ('wagglyblog_post_detail',
                (self.pub_date.year, self.pub_date.month, self.pub_date.day, self.slug))

    @permalink
    def get_author_url(self):
        return ('wagglyblog_author', (self.author,))

    def get_next_published(self):
        try:
            return Post.published.filter(pub_date__gt=self.pub_date).order_by(('pub_date'))[0]
        except IndexError:
            return None

    def get_previous_published(self):
        try:
            return Post.published.filter(pub_date__lt=self.pub_date)[0]
        except IndexError:
            return None

    @property
    def category_list(self):
        """Generates a comma-separated list of categories the specific post is in.
        The default Category -> string conversion is used (`unicode(category)`)
        """
        if self.categories.all():
            return u", ".join(unicode(cat) for cat in self.categories.all())
        else:
            return u""

